#include "xmainloop.h"

#include "scene_mgr.h"
#include "event_base.h"
#include "g_graphics.h"
#include "graphics_window.h"
#include "xge.h"


#include <windows.h>


namespace xge{


  using event::EventManager;
  using graphics::SceneManager;
  using window::GraphicsWindow;


  void MainLoop::Loop() {
    // Iterating everything here !
    // Get the HWND of this window is 
    HWND hwnd ;
    MSG msg;
    Timer::tick_t used_time_diff ;
    // get the primary window 
    GraphicsWindow* primary_window = XGameEngine::GetGraphics2D()->GetGraphicsWindow();
    // fetch the window hwnd value
    primary_window->GetPlatformHandler( (void**)(&hwnd) );
    // setting up the timer stuff here
    // We setting up the high precision timer 
    timer_.BeginTimerCounting(1);
    while( true ) {
      // Sync for the timer
      used_time_diff = timer_.TimeDiff();
      // we have at-least enter the loop in the second time 
      // so we tick the OnIdle stuff here
      last_loop_time_ = used_time_diff;
      // lets schedule the on idle message 
      if( used_time_diff < time_ ) {
        // ok , we have some time to use here
        if(on_idle_listener_) {
          timer_.TimeDiff();
          on_idle_listener_->OnIdle();
          last_loop_time_+=timer_.TimeDiff();
        }
        // Let's check if we should sleep or not
        if( last_loop_time_ < time_  ) {
          // We have save some time here , so we 
          // sleep a while 
          Sleep( time_- last_loop_time_ );
          last_loop_time_ = time_;
        }
      }
      // fetch the message internally from Windows message queue
      // There may be many message , however , we should check them
      // until no more message here !
      while( PeekMessage(&msg,hwnd,0,0,PM_REMOVE) ) {
        DispatchMessage(&msg);
        // Here comes our beautiful message .
        if( msg.message == WM_QUIT ) {
          // We do not have to call anything , because the only reason 
          // that we receive this message is that the user has press the
          // exit button of the window or do it manually . 
          quit_ = true;
          goto __finish ;
        }
      }
      // Until now , we have not handled any user message , we should tick 
      // If we have been switched the focus , we just sleep here ...
      if( ::GetFocus() == hwnd ) {
        // tick the timer
        // tick the event manager
        event_mgr_->Loop(last_loop_time_);
        // checking the internal states that if we need to quit here
        if( quit_ )
          goto __finish;
        // tick the scene graph 
        scene_mgr_->Loop(last_loop_time_);
        // checking the internal states that if we need to quit here
        if( quit_ )
          goto __finish;
      }

    }

    // When reaching the finish , that means the Windows Procedure Function has been 
    // notified the quit message , what is more , we need to destroy everything .
    // Internally , this is done by the user , not by us , we just return , and do
    // nothing!
__finish:
    SYS_LOG(INFO,false,_xT("MainLoop has been notified with quit message ,") 
      _xT("therefore , say good bye to our application!"));
    return;
  }


  void MainLoop::QuitApplication() {
    // quit application 
    quit_ = true ;
    // we must call PostQuitMessage(0) to invoke the
    // graphics_window OnExitListener 
    ::PostQuitMessage(0);
  }

}// namespace xge